$import( "SmitearWebGL.Programs.AbstractProgram" );

SmitearWebGL.Programs.LightPrePass.SpecularProgram = SmitearWebGL.Programs.AbstractProgram.extend(
{
	/******** constructor ********/
	
	init : function()
	{
		this._super();
		this._registClass( "SmitearWebGL.Programs.LightPrePass.SpecularProgram" );
	}
	,
	
	/******** public method ********/
	
	activeUniform : function( renderSession, renderableObject )
	{
		var frustumCoordsBuffer = renderSession.camera.getFrustumBuffer();
		var hr = SmitearWebGL.Core.HResult.SUCCESS;
		hr |= frustumCoordsBuffer.bind();
		hr |= frustumCoordsBuffer.active( this._shader );
		
		for ( i = 0; i < renderableObject._textures.length; i ++ )
		{
			var texture = renderableObject.getTextureAt( i );
			
			if ( texture && texture.getGlTextureTarget() )
			{
				switch ( texture.usage )
				{
					case SmitearWebGL.Renderer.LPPRenderer.RTUsage.FBO_DEPTH_TEX :
						this.context.gl.activeTexture( this.context.gl.TEXTURE0 + i );
						this.context.gl.bindTexture( texture.getGlTextureTarget(), texture.getGlTexture() );
						this.context.gl.uniform1i( this._shader.uniforms.uDepthMap.location, i );
						break;
						
					case SmitearWebGL.Renderer.LPPRenderer.RTUsage.FBO_NORMAL_TEX :
						this.context.gl.activeTexture( this.context.gl.TEXTURE0 + i );
						this.context.gl.bindTexture( texture.getGlTextureTarget(), texture.getGlTexture() );
						this.context.gl.uniform1i( this._shader.uniforms.uNormalMap.location, i );
						break;
				}
			}
		}
		
		return hr;
	}
	,
	
	/******** private method ********/
	
	_generateVertexShaderStr : function()
	{
		this._super();
		
		var vertStr =
		"\
		attribute vec3 " + SmitearWebGL.Resources.Buffer.AttribLocation.POSITION +";\n\
		attribute vec3 " + SmitearWebGL.Resources.Buffer.AttribLocation.FRUSTUMCOORDS +";\n\
		varying vec2 vTexCoord;\n\
		varying vec3 vFrustumCornerVS;\n\
		void main(void)\n\
		{\n\
		vec4 pos = vec4(" + SmitearWebGL.Resources.Buffer.AttribLocation.POSITION +", 1.0);\n\
		gl_Position = pos;\n\
		vTexCoord = vec2((pos.x + 1.0) * 0.5, (pos.y + 1.0) * 0.5);\n\
		vFrustumCornerVS = " + SmitearWebGL.Resources.Buffer.AttribLocation.FRUSTUMCOORDS +";\n\
		}\n\
		";
		
		return vertStr;
	}
	,
	_generateFragmentShaderStr : function()
	{
		this._super();
		
		return "";
	}
}
);

SmitearWebGL.Programs.LightPrePass.DirLightSpecularProgram = SmitearWebGL.Programs.LightPrePass.SpecularProgram.extend(
{
	/******** constructor ********/
	
	init : function()
	{
		this._super();
		this._registClass( "SmitearWebGL.Programs.LightPrePass.DirLightSpecularProgram" );
	}
	,
	activeLightUniform : function( light )
	{
		light.glUniform( SmitearWebGL.ShaderUniform.lightColor, this._shader );
		light.glUniform( SmitearWebGL.ShaderUniform.lightIntensity, this._shader );
		light.glUniform( SmitearWebGL.ShaderUniform.lightDirection, this._shader );
		
		return SmitearWebGL.Core.HResult.SUCCESS;
	}
	,
	_generateFragmentShaderStr : function()
	{
		this._super();
		
		var fragStr = 
		"\
		#ifdef GL_ES\n\
		precision highp float;\n\
		#endif\n\
		uniform vec3 uLightDir;\n\
		uniform vec3 uLightColor;\n\
		uniform float uLightIntensity;\n\
		varying vec2 vTexCoord;\n\
		varying vec3 vFrustumCornerVS;\n\
		uniform sampler2D uDepthMap;\n\
		uniform sampler2D uNormalMap;\n\
		const vec4 bitShifts = vec4(5.960464477539063e-8, 0.0000152587890625, 0.00390625, 1.0);\n\
		\n\
		vec4 lighting(vec3 normal, float depth, float shininess)\n\
		{\n\
			vec3 pos = vFrustumCornerVS * depth;\n\
			vec3 eyevec = - normalize(pos);\n\
			vec3 lightvec =  normalize(uLightDir);\n\
			vec3 h = normalize(eyevec + lightvec);\n\
			float specvalue = 0.0;\n\
			float dotH = dot(h, normal);\n\
			if(dotH > 0.0)\n\
			{\n\
				specvalue = pow(dotH, shininess) * uLightIntensity;\n\
			}\n\
			return vec4(uLightColor * specvalue, 1.0);\n\
		}\n\
		\n\
		void main(void)\n\
		{\n\
			float depth = dot(texture2D(uDepthMap, vTexCoord), bitShifts);\n\
			if (depth > 0.0)\n\
			{\n\
				vec4 ns = texture2D(uNormalMap, vTexCoord);\n\
				vec3 normal = ns.xyz * 2.0 - 1.0;\n\
				gl_FragColor = lighting(normal, depth, ns.a * 1024.0);\n\
			}\n\
			else\n\
			{\n\
				gl_FragColor = vec4(0.0, 0.0, 0.0, 0.0);\n\
			}\n\
		}\n\
		";
		
		return fragStr;
	}
}
);

SmitearWebGL.Programs.LightPrePass.PointLightSpecularProgram = SmitearWebGL.Programs.LightPrePass.SpecularProgram.extend(
{
	/******** constructor ********/
	
	init : function()
	{
		this._super();
		this._registClass( "SmitearWebGL.Programs.LightPrePass.PointLightSpecularProgram" );
	}
	,
	activeLightUniform : function( light )
	{
		light.glUniform( SmitearWebGL.ShaderUniform.lightColor, this._shader );
		light.glUniform( SmitearWebGL.ShaderUniform.lightIntensity, this._shader );
		light.glUniform( SmitearWebGL.ShaderUniform.lightPosition, this._shader );
		
		return SmitearWebGL.Core.HResult.SUCCESS;
	}
	,
	_generateFragmentShaderStr : function()
	{
		this._super();
		
		var fragStr = 
		"\
		#ifdef GL_ES\n\
		precision highp float;\n\
		#endif\n\
		uniform vec3 uLightPos;\n\
		uniform vec3 uLightColor;\n\
		uniform float uLightIntensity;\n\
		varying vec2 vTexCoord;\n\
		varying vec3 vFrustumCornerVS;\n\
		uniform sampler2D uDepthMap;\n\
		uniform sampler2D uNormalMap;\n\
		const vec4 bitShifts = vec4(5.960464477539063e-8, 0.0000152587890625, 0.00390625, 1.0);\n\
		\n\
		vec4 lighting(vec3 normal, float depth, float shininess)\n\
		{\n\
			vec3 pos = vFrustumCornerVS * depth;\n\
			vec3 eyevec = - normalize(pos);\n\
			vec3 lightvec = normalize(uLightPos - pos);\n\
			vec3 h = normalize(eyevec + lightvec);\n\
			float specvalue = 0.0;\n\
			float dotH = dot(h, normal);\n\
			if(dotH > 0.0)\n\
			{\n\
				specvalue = uLightIntensity * pow(dotH, shininess);\n\
			}\n\
			return vec4(uLightColor * specvalue, 1.0);\n\
		}\n\
		\n\
		void main(void)\n\
		{\n\
			float depth = dot(texture2D(uDepthMap, vTexCoord), bitShifts);\n\
			if (depth > 0.0)\n\
			{\n\
				vec4 ns = texture2D(uNormalMap, vTexCoord);\n\
				vec3 normal = ns.xyz * 2.0 - 1.0;\n\
				gl_FragColor = lighting(normal, depth, ns.a * 1024.0);\n\
			}\n\
			else\n\
			{\n\
				gl_FragColor = vec4(0.0, 0.0, 0.0, 0.0);\n\
			}\n\
		}\n\
		";
		
		return fragStr;
	}
}
);

SmitearWebGL.Programs.LightPrePass.SpotLightSpecularProgram = SmitearWebGL.Programs.LightPrePass.SpecularProgram.extend(
{
	/******** constructor ********/
	
	init : function()
	{
		this._super();
		this._registClass( "SmitearWebGL.Programs.LightPrePass.SpotLightSpecularProgram" );
	}
	,
	activeLightUniform : function( light )
	{
		light.glUniform( SmitearWebGL.ShaderUniform.lightColor, this._shader );
		light.glUniform( SmitearWebGL.ShaderUniform.lightIntensity, this._shader );
		light.glUniform( SmitearWebGL.ShaderUniform.lightPosition, this._shader );
		light.glUniform( SmitearWebGL.ShaderUniform.lightDirection, this._shader );
		light.glUniform( SmitearWebGL.ShaderUniform.lightSpotOuterCone, this._shader );
		light.glUniform( SmitearWebGL.ShaderUniform.lightSpotInnerCone, this._shader );
		light.glUniform( SmitearWebGL.ShaderUniform.lightSpotExponent, this._shader );
		
		return SmitearWebGL.Core.HResult.SUCCESS;
	}
	,
	_generateFragmentShaderStr : function()
	{
		this._super();
		
		var fragStr = 
		"\
		#ifdef GL_ES\n\
		precision highp float;\n\
		#endif\n\
		uniform vec3 uLightPos;\n\
		uniform vec3 uLightDir;\n\
		uniform vec3 uLightColor;\n\
		uniform float uLightIntensity;\n\
		uniform float uSpotOuterCone;\n\
		uniform float uSpotInnerCone;\n\
		uniform float uSpotExp;\n\
		varying vec2 vTexCoord;\n\
		varying vec3 vFrustumCornerVS;\n\
		uniform sampler2D uDepthMap;\n\
		uniform sampler2D uNormalMap;\n\
		const vec4 bitShifts = vec4(5.960464477539063e-8, 0.0000152587890625, 0.00390625, 1.0);\n\
		\n\
		vec4 lighting(vec3 normal, float depth, float shininess)\n\
		{\n\
			vec3 pos = vFrustumCornerVS * depth;\n\
			vec3 eyevec = - normalize(pos);\n\
			vec3 lightvec = normalize(uLightPos - pos);\n\
			vec3 h = normalize(eyevec + lightvec);\n\
			float specvalue = 0.0;\n\
			float spotEffect = dot(lightvec, -uLightDir);\n\
			if (spotEffect > uSpotOuterCone)\n\
			{\n\
				if (spotEffect > uSpotInnerCone)\n\
					spotEffect = 1.0;\n\
				else\n\
					spotEffect = pow(spotEffect, uSpotExp);\n\
				float dotH = dot(h, normal);\n\
				if(dotH > 0.0)\n\
				{\n\
					specvalue = spotEffect * uLightIntensity * pow(dotH, shininess);\n\
				}\n\
			}\n\
			return vec4(uLightColor * specvalue, 1.0);\n\
		}\n\
		\n\
		void main(void)\n\
		{\n\
			float depth = dot(texture2D(uDepthMap, vTexCoord), bitShifts);\n\
			if (depth > 0.0)\n\
			{\n\
				vec4 ns = texture2D(uNormalMap, vTexCoord);\n\
				vec3 normal = ns.xyz * 2.0 - 1.0;\n\
				gl_FragColor = lighting(normal, depth, ns.a * 1024.0);\n\
			}\n\
			else\n\
			{\n\
				gl_FragColor = vec4(0.0, 0.0, 0.0, 0.0);\n\
			}\n\
		}\n\
		";
		
		return fragStr;
	}
}
);